package com.gitee.minimalismstyle.fresh.simple.controller

import com.gitee.minimalismstyle.fresh.common.core.domain.R
import com.gitee.minimalismstyle.fresh.simple.api.service.DatabaseService
import com.gitee.minimalismstyle.fresh.simple.model.Codegen
import com.gitee.minimalismstyle.fresh.simple.model.CodegenTemplate
import org.apache.commons.io.FileUtils
import org.beetl.core.Configuration
import org.springframework.web.bind.annotation.*
import org.beetl.core.GroupTemplate
import org.beetl.core.Template
import org.beetl.core.resource.FileResourceLoader
import java.io.File


@RestController
@RequestMapping("codegen")
class CodegenController(private val databaseService: DatabaseService) {


    companion object {
        var tmpdir = System.getProperty("java.io.tmpdir")
        val root = CodegenController::class.java.getResource("/codegen").path
        val resourceLoader = FileResourceLoader(root, "utf-8")
        val cfg: Configuration = Configuration.defaultConfiguration()
        val gt = GroupTemplate(resourceLoader, cfg)

        val bizKtRootPath = "\\fresh\\modules\\fresh-%1\$s\\fresh-%1\$s-biz\\src\\main\\kotlin\\com\\gitee\\minimalismstyle\\fresh\\%1\$s"
        val apiKtRootPath = "\\fresh\\modules\\fresh-%1\$s\\fresh-%1\$s-api\\src\\main\\kotlin\\com\\gitee\\minimalismstyle\\fresh\\%1\$s\\api"
        val resourcesRootPath = "\\fresh\\modules\\fresh-%1\$s\\fresh-%1\$s-biz\\src\\main\\resources"
        val tsRootPath = "\\fresh-admin\\src\\app\\routes\\%1\$s"
        val tsApiRootPath = "\\fresh-admin\\src\\app\\api\\%1\$s"

        val templateMap = mapOf<String, List<CodegenTemplate>>(
                "entity" to listOf<CodegenTemplate>(CodegenTemplate("$bizKtRootPath\\entity\\%2\$s.kt", "entity.btl")),
                "sql" to listOf<CodegenTemplate>(CodegenTemplate("$resourcesRootPath\\sql\\%3\$s.md", "sql.btl")),
                "dao" to listOf<CodegenTemplate>(CodegenTemplate("$bizKtRootPath\\dao\\%2\$sDao.kt", "dao.btl")),
                "dto" to listOf<CodegenTemplate>(CodegenTemplate("$apiKtRootPath\\dto\\%2\$sDto.kt", "dto.btl")),
                "model" to listOf<CodegenTemplate>(CodegenTemplate("$apiKtRootPath\\model\\%2\$s.kt", "model.btl")),
                "service" to listOf<CodegenTemplate>(
                        CodegenTemplate("$apiKtRootPath\\service\\%2\$sService.kt", "service.btl"),
                        CodegenTemplate("$bizKtRootPath\\service\\impl\\%2\$sServiceImpl.kt", "serviceImpl.btl")
                ),
                "controller" to listOf<CodegenTemplate>(CodegenTemplate("$bizKtRootPath\\controller\\%2\$sController.kt", "controller.btl")),
                "list" to listOf<CodegenTemplate>(
                        CodegenTemplate("$tsRootPath\\%3\$s\\%3\$s.component.ts", "list.component.ts.btl"),
                        CodegenTemplate("$tsRootPath\\%3\$s\\%3\$s.component.html", "list.component.html.btl")
                ),
                "edit" to listOf<CodegenTemplate>(
                        CodegenTemplate("$tsRootPath\\%3\$s\\edit\\edit.component.ts", "edit.component.ts.btl"),
                        CodegenTemplate("$tsRootPath\\%3\$s\\edit\\edit.component.html", "edit.component.html.btl")
                ),
                "servicets" to listOf<CodegenTemplate>(
                        CodegenTemplate("$tsRootPath\\model\\%3\$s.model.ts", "model.ts.btl"),
                        CodegenTemplate("$tsRootPath\\service\\%3\$s.service.ts", "service.ts.btl")
                )

        )
    }

    @PostMapping("generate")
    fun generate(@RequestBody codegen: Codegen): R<Any> {
        var params: MutableMap<String, Any> = mutableMapOf()
        params.put("USDChar", "$")
        params.put("model", codegen.model!!)
        params.put("modelClassName", codegen.model?.replaceFirstChar {it.uppercase() }!!)
        params.put("modelCtx", "\${" + codegen.model?.replaceFirstChar {it.uppercase() }!! + "ApiConst.CTX}")
        params.put("author", codegen.author!!)
        codegen.names.forEach { name ->
            val table = databaseService.findTableByName(codegen.datasourceId!!, name).get()
            params.put("table", table)
            codegen.targets.forEach { target ->
                val codegenTemplates: List<CodegenTemplate> = templateMap[target]!!
                codegenTemplates.forEach {
                    val path = codegen.rootPath +
                            String.format(it.filePath, codegen.model, table.className, table.objectName)
                    val file = File(path)
                    val str = generateTarget(it.templateName, params)
                    FileUtils.writeStringToFile(file, str)
                }
            }
        }
        return R.success()
    }

    private fun generateTarget(templateName: String, params: Map<String, Any>): String {
        val t: Template = gt.getTemplate(templateName)
        t.binding(params)
        val str: String = t.render()
        return str
    }
}
